package com.wk.database.entity;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.LinkedList;
import java.util.List;

import com.wk.database.entity.definition.Column;
import com.wk.database.entity.definition.PrimaryKey;
import com.wk.database.entity.definition.Table;

public class EntityAnalyzer {
	/**
	 * 获取实体类的无参构造器
	 * 
	 * @param entity
	 *            实体类的类型
	 * @return 无参构造器
	 * @throws NoDefaultConstructorException
	 *             实体类的无参构造器不可访问
	 */
	public static <Entity> Constructor<Entity> findConstructor(Class<Entity> entity)
			throws NoDefaultConstructorException {
		try {
			return entity.getConstructor();
		} catch (NoSuchMethodException e) {
			throw new NoDefaultConstructorException(entity, e);
		} catch (SecurityException e) {
			throw new NoDefaultConstructorException(entity, e);
		}
	}

	/**
	 * 获取实体类对应的数据库表
	 * 
	 * @param entity
	 *            实体类的类型
	 * @return 表名
	 * @throws NoTableSpecifiedException
	 *             未指定数据库表，即实体类不带有{@link Table}注解
	 */
	public static <Entity> String findTable(Class<Entity> entity) throws NoTableSpecifiedException {
		if (!entity.isAnnotationPresent(Table.class)) {
			throw new NoTableSpecifiedException(entity);
		}

		return entity.getAnnotation(Table.class).value();
	}

	/**
	 * 获取实体类的映射到数据库的字段
	 * 
	 * @param entity
	 *            实体类的类型
	 * @return 容器，每个元素是一个字段<br>
	 *         这些字段都带有{@link Column}注解
	 * @throws NoMappedFieldException
	 *             未指定要映射到数据库表的字段，即实体类的字段不带有{@link Column}
	 */
	public static <Entity> List<Field> findMappedFields(Class<Entity> entity) throws NoMappedFieldException {
		List<Field> results = new LinkedList<>();
		Field[] fields = entity.getDeclaredFields();
		for (Field field : fields) {
			if (field.isAnnotationPresent(Column.class)) {
				results.add(field);
			}
		}

		if (results.isEmpty()) {
			throw new NoMappedFieldException(entity);
		}

		return results;
	}

	public static <Entity> ClassifiedFields classifyMappedFields(Class<Entity> entity)
			throws NoMappedIdentifierException, NoMappedFieldException {
		ClassifiedFields results = new ClassifiedFields(entity);

		Field[] fields = entity.getDeclaredFields();
		for (Field field : fields) {
			if (field.isAnnotationPresent(Column.class)) {
				if (field.isAnnotationPresent(PrimaryKey.class)) {
					results.addIdentifierField(field);
				} else {
					results.addCommonField(field);
				}
			}
		}
		
		results.validate();

		return results;
	}
}
